package com.oig.sys.file.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.http.ContentType;
import com.oig.common.constants.CommonConstants;
import com.oig.common.exception.BadRequestException;
import com.oig.common.exception.ServiceException;
import com.oig.sys.file.dto.FileInfoDto;
import com.oig.sys.file.service.IFileUploadService;
import com.oig.sys.file.service.ITbBusFileConfigService;
import com.oig.sys.file.vo.BusFileConfigVo;
import com.oig.sys.file.vo.UploadVo;
import com.oig.sys.minio.core.MinIOTemplate;
import com.oig.sys.minio.util.ObjectNameUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

@Component
@Slf4j
@RequiredArgsConstructor
public class FileUploadServiceImpl implements IFileUploadService {

    private final MinIOTemplate minIOTemplate;
    private final ITbBusFileConfigService busFileConfigService;


    @Override
    public UploadVo upload(MultipartFile file) {
        UploadVo uploadVo = new UploadVo();
        uploadVo.setFileName(file.getOriginalFilename());
        uploadVo.setFileSize(file.getSize());
        if (file.getContentType() == null) {
            uploadVo.setFileType(ContentType.OCTET_STREAM.getValue());
        } else {
            uploadVo.setFileType(file.getContentType());
        }
        try {
            return this.dealFile(file, uploadVo);
        } catch (Exception e) {
            log.error("upload io error", e);
            throw new ServiceException(e.getMessage());
        }
    }

    private UploadVo dealFile(MultipartFile file, UploadVo uploadVo) throws Exception {
        String fileName = file.getOriginalFilename();
        if (fileName == null) {
            throw new BadRequestException("file Name is null..");
        }
        if (fileName.lastIndexOf(CommonConstants.DOT_STR) <= 0) {
            throw new BadRequestException("文件没有后缀名，不支持上传");
        }
        String prefix = fileName.substring(fileName.lastIndexOf(CommonConstants.DOT_STR));
        String objectName = IdUtil.fastSimpleUUID() + prefix;
        log.debug("upload file name: {}", objectName);
        String tempBucket = minIOTemplate.getTempBucket();
        String objPath = this.minIOTemplate.putObject(tempBucket, objectName, file.getInputStream(), file.getSize(), uploadVo.getFileType());
        log.debug("upload success: {}", objPath);
        uploadVo.setFileId(objPath);
        String newObjectName = objPath.substring(objPath.indexOf(ObjectNameUtil.FILE_SPLIT_PATH) + 1);
        String expUrl = this.minIOTemplate.getObjectURL(tempBucket, newObjectName);
        uploadVo.setFileUrl(expUrl.substring(0, expUrl.lastIndexOf("?")));
        return uploadVo;
    }


    @Override
    public List<UploadVo> upload(MultipartFile[] files) {
        if (files == null || files.length == 0) {
            throw new BadRequestException("空文件");
        }
        List<UploadVo> idList = new ArrayList<>();
        for (MultipartFile file : files) {
            if (file == null || file.getSize() == 0 || StrUtil.isBlank(file.getOriginalFilename())) {
                continue;
            }
            UploadVo uploadVo = new UploadVo();
            log.info("upload file:{},{},{},{}", file.getName(), file.getContentType(), file.getSize(), file.getOriginalFilename());
            uploadVo.setFileName(file.getOriginalFilename());
            uploadVo.setFileSize(file.getSize());
            if (file.getContentType() == null) {
                uploadVo.setFileType(ContentType.OCTET_STREAM.getValue());
            } else {
                uploadVo.setFileType(file.getContentType());
            }
            try {
                this.dealFile(file, uploadVo);
            } catch (IOException e) {
                log.error("upload io error", e);
                uploadVo.setErrMsg(e.getMessage());
            } catch (Exception e) {
                log.error("upload error", e);
                uploadVo.setErrMsg(e.getMessage());
            }
            idList.add(uploadVo);
        }
        return idList;
    }


    @Override
    public String moveBucket(String fileId, String businessType, String relationType) {
        if (!fileId.contains(minIOTemplate.getTempBucket())) {
            return fileId;
        }
        BusFileConfigVo configVo = busFileConfigService.findConfig(businessType, relationType);
        try {
            String oldObjectName = fileId.substring(minIOTemplate.getTempBucket().length() + 1);
            return this.minIOTemplate.copyAndDelTempObject(oldObjectName, configVo.getBucketName());
        } catch (Exception e) {
            throw new ServiceException("文件挪桶失败");
        }
    }


    @Override
    public String getPutUrl(String businessType, String relationType, String fileName) {
        BusFileConfigVo configVo = busFileConfigService.findConfig(businessType, relationType);
        if (configVo == null) {
            throw new ServiceException("存储配置不存在");
        }
        return this.minIOTemplate.getPutObjectURL(configVo.getBucketName(), fileName, 2 * 60);
    }

    @Override
    public String getDownloadUrl(String fileId) {
        if (fileId != null && fileId.indexOf(ObjectNameUtil.FILE_SPLIT_PATH) > 0) {
            String objectName = fileId.substring(fileId.indexOf(ObjectNameUtil.FILE_SPLIT_PATH) + 1);
            String bucket = fileId.substring(0, fileId.indexOf(ObjectNameUtil.FILE_SPLIT_PATH));
            return this.minIOTemplate.getObjectURL(bucket, objectName);
        }
        return null;
    }

    @Override
    public void removeFile(String fileId) {
        if (fileId != null) {
            try {
                String objectName = fileId.substring(fileId.indexOf(ObjectNameUtil.FILE_SPLIT_PATH) + 1);
                String bucket = fileId.substring(0, fileId.indexOf(ObjectNameUtil.FILE_SPLIT_PATH));
                this.minIOTemplate.removeObject(bucket, objectName);    //删除旧文件
            } catch (Exception e) {
                log.warn("{} 文件清除失败", fileId);
            }
        }
    }

    @Override
    public void batchDownLoad(List<FileInfoDto> fileList, HttpServletResponse response) {
        int i = 0;
        int j = 1;
        try {
            //被压缩文件流集合
            InputStream[] srcFiles = new InputStream[fileList.size()];
            //被压缩文件名称
            String[] srcFileNames = new String[fileList.size()];

            List<String> fileNames = new ArrayList<>();
            for (FileInfoDto fileInfoDto : fileList) {
                String oldBucket = fileInfoDto.getFileId().substring(0, fileInfoDto.getFileId().indexOf(ObjectNameUtil.FILE_SPLIT_PATH));
                String oldObjectName = fileInfoDto.getFileId().substring(fileInfoDto.getFileId().indexOf(ObjectNameUtil.FILE_SPLIT_PATH) + 1);
                InputStream ins = this.minIOTemplate.getObject(oldBucket, oldObjectName);
                //塞入流数组中
                srcFiles[i] = ins;
                String fileName = fileInfoDto.getFileName();
                //重复的文件名下载后在后面加1
                if (fileNames.contains(fileName)) {
                    fileName = "重复附件" + j + "-" + fileName;
                    j++;
                    fileNames.add(fileName);
                } else {
                    fileNames.add(fileName);
                }
                srcFileNames[i] = fileName;
                i++;
            }
            response.setCharacterEncoding("UTF-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("htdz.zip", "UTF-8"));
            //多个文件压缩成压缩包返回
            ZipUtil.zip(response.getOutputStream(), srcFileNames, srcFiles);
        } catch (IOException e) {
            log.error("批量下载异常，, errormsg：{}", e.getMessage());
            throw new ServiceException("批量下载异常,请检查文件服务器是否存在改文件");
        }
    }
}
